package com.caocaog.market.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.caocaog.market.annotation.IgnoreAuth;
import com.caocaog.market.dms.service.DmsService;
import com.caocaog.market.entity.OrderBase;
import com.caocaog.market.entity.OrderPay;
import com.caocaog.market.pay.UnionPay;
import com.caocaog.market.pay.syb.config.SybConfig;
import com.caocaog.market.pay.syb.utils.SybUtil;
import com.caocaog.market.service.IOrderBaseService;
import com.caocaog.market.service.IOrderPayService;
import com.caocaog.market.toccpt.service.ApiForOrderService;
import com.ijpay.core.kit.WxPayKit;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.vo.Result;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

/**
 * @Description: pay notify
 * @author: Yuki Guo
 * @date: 2021年11月01日 11:34
 */

@RestController
@RequestMapping("/api/order/notify")
@Slf4j
@Api(value = "orderNotify", tags = "支付回调")
public class OrderPayNotifyController {
    @Autowired
    private UnionPay unionPay;
    @Autowired
    private IOrderBaseService orderBaseService;
    @Autowired
    private ApiForOrderService apiForOrderService;
    @Autowired
    private IOrderPayService orderPayService;
    @Resource
    private DmsService dmsService;

    // 写死的内容，测试使用
    @IgnoreAuth
    @GetMapping("/test_km_money")
    public void abc(){
        Result result = apiForOrderService.dealMarketAutomaticOrder("P20220413093814268522321");
        log.info("向曹操跑腿甩单并存甩单记录 isSuccess:" + result.isSuccess() + " " + result.getMessage());
    }
    /**
     * 回调逻辑处理:同步结算记录
     *
     * @param payNo 订单交易id
     */
    @IgnoreAuth
    // @Transactional
    @RequestMapping("nofitytest")
//    @ApiOperation(value = "回调逻辑处理:同步结算记录", notes = "回调逻辑处理:同步结算记录")
    public void logicHandle(String payNo) {
        log.info("回调验证签名成功，开始处理逻辑:同步结算记录。。。。。");
        //处理成功逻辑
        System.out.println(payNo);
        // 同步结算记录
        orderBaseService.localHandler(payNo);
        // 向曹操跑腿甩单并存甩单记录；自动甩单（会检测门店设置的发单模式，如果是自动发单就向曹操跑腿进行甩单，如果是手动发单则不会向曹操跑腿进行甩单）
//        Result result = apiForOrderService.dealMarketAutomaticOrder(payNo);
        Result result =  dmsService.sendOrderToDMS(payNo);//向DMS7发单
        log.info("向曹操跑腿甩单并存甩单记录 isSuccess:" + result.isSuccess() + " " + result.getMessage());
        if (result.isSuccess()) {
            //发单成功 更新用户订单为2待收货
            OrderPay orderPay = orderPayService.getOne(new QueryWrapper<OrderPay>().eq("pay_serno", payNo));
            OrderBase orderBase = orderBaseService.getById(orderPay.getOrderId());
            log.info("发单成功 更新用户订单为2待收货" + orderBase.getOrderNo() + " " + orderBase.getStatus());
            orderBase.setStatus("2");
            orderBaseService.updateById(orderBase);
            orderBaseService.addOrderStatusInfo(orderBase.getId(), orderBase.getOrderNo(), "", "", "商家已接单", new Date());
        }

    }

    /**
     * 微信支付成功回调方法
     * @return 回调结果
     */
    @IgnoreAuth
    @RequestMapping(value = "/wx", method = {RequestMethod.GET, RequestMethod.POST})
    public String wxNofity() {
        log.info("微信订单支付回调->>>>>>>>>");
        Result<?> result = unionPay.wxNotify();
        if (result.isSuccess()) {
            //订单号
            JSONObject jsonObject = (JSONObject) result.getResult();
            String payNo = jsonObject.getString("payNo");
//            this.logicHandle(payNo);
            return wxResult(true);
        }
        return wxResult(false);
    }

    @Resource
    RedissonClient redissonClient;
    private final static String ORDER_LOCK_KEY = "sybNotify:lockOrderId";
    /**
     * 通联订单支付回调
     */
    @ResponseBody
    @RequestMapping(value = "/sybNotify", method = RequestMethod.POST)
    public void sybPayCallback(HttpServletRequest request, HttpServletResponse response) throws Exception {
        log.warn("通联回调开始");
        //通知传输的编码为GBK
        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");

        //动态遍历获取所有收到的参数,此步非常关键,因为收银宝以后可能会加字段,动态获取可以兼容
        TreeMap<String,String> params = getParams(request);

//        String orderId = params.get("cusorderid");
        String orderId = params.get("trxid");
        RLock lock = redissonClient.getLock(ORDER_LOCK_KEY + orderId);

        try {
            if(lock != null) {
                if (lock.tryLock()) {
                    log.info("尝试获取redis锁成功");
                    String appkey = "";
                    if ("RSA".equals(params.get("signtype"))) {
                        appkey = SybConfig.SYB_RSATLPUBKEY;
                    } else if ("SM2".equals(params.get("signtype"))) {
                        appkey = SybConfig.SYB_SM2TLPUBKEY;
                    } else {
                        appkey = SybConfig.SYB_MD5_APPKEY;
                    }
                    boolean isSign = SybUtil.validSign(params, appkey, params.get("signtype"));// 接受到推送通知,首先验签
                    log.info("验签结果:" + isSign);
                    Result<?> result = unionPay.sybNotify(params);
                    if (result.isSuccess()) {
                        this.logicHandle(orderId);
                        response.getOutputStream().write("success".getBytes());
                    }
                }else {
                    log.info("尝试获取锁失败");
                    response.getOutputStream().write("error".getBytes());
                }
            }else {
                response.getOutputStream().write("error".getBytes());
            }
            response.flushBuffer();
        } catch (Exception e) {//处理异常
            log.error("通联订单支付回调失败:",e);
            response.getOutputStream().write("error".getBytes());
            response.flushBuffer();
        }finally {
            //判断该lock是否已经锁
            if (lock!=null) {
                //判断锁是否是自己的
                if (lock.isHeldByCurrentThread()) {
                    lock.unlock();
                }
            }
        }
    }

    /**
     * 动态遍历获取所有收到的参数,此步非常关键,因为收银宝以后可能会加字段,动态获取可以兼容由于收银宝加字段而引起的签名异常
     */
    private TreeMap<String, String> getParams(HttpServletRequest request){
        TreeMap<String, String> map = new TreeMap<String, String>();
        Map reqMap = request.getParameterMap();
        for(Object key:reqMap.keySet()){
            String value = ((String[])reqMap.get(key))[0];
            map.put(key.toString(),value);
        }
        return map;
    }

    /**
     * 微信退款回调方法
     */
    @RequestMapping(value = "/wxRefund", method = {RequestMethod.GET, RequestMethod.POST})
    public void wxRefundNofity() {
        log.info("微信订单退款支付回调->>>>>>>>>");
        Result<?> result = unionPay.wxRefundNotify();
        log.error("订单退款支付回调->>>>>>>>>" + result.isSuccess() + result.getMessage());
    }


    @ApiOperation(value = "抖音微信订单回调接口")
    @RequestMapping(value = "/notify", method = RequestMethod.POST, produces = "text/html;charset=UTF-8")
    @ResponseBody
    public JSONObject bdNotify(HttpServletRequest request, HttpServletResponse response) {
        log.info("字节小程序通用回调");
        JSONObject result = new JSONObject();
        try {
            request.setCharacterEncoding("utf-8");
            response.setCharacterEncoding("utf-8");
            response.setContentType("text/html;charset=UTF-8");
            response.setHeader("Access-Control-Allow-Origin", "*");
            InputStream in = request.getInputStream();
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len;
            while ((len = in.read(buffer)) != -1) {
                out.write(buffer, 0, len);
            }
            out.close();
            in.close();
            String responseJson = new String(out.toByteArray(),"utf-8");
            log.info("responseJson：{}",responseJson);
            JSONObject object = JSON.parseObject(responseJson);
            JSONObject msg = object.getJSONObject("msg");
            // 回调类型 0支付 1退款 2结算及分账
            String type = msg.getString("cp_extra");
            log.info("回调类型(0支付 1退款 2结算及分账) -> " + type);
            if (type.equals("0")) {
                result = unionPay.bdNotify(object);
                if (result.getInteger("err_no") == 0) {
                    this.logicHandle(msg.getString("cp_orderno"));
                }
            } else if (type.equals("1")) {
                result = unionPay.bdRefundNotify(object);
            }
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            result.put("err_no",8);
            result.put("err_tips","error");
            return result;
        }
    }


    /**
     * 订单支付 支付宝回调
     *
     * @return
     */
   /* @RequestMapping(value = "/ali", method = {RequestMethod.POST, RequestMethod.GET})
    public String aliVipOrderNotify() {
        System.out.println("支付宝冲冲冲");
        log.info("支付宝支付活动订单支付回调->>>>>>>>>");
        Result<?> result = unionPay.aliNotify();
        System.out.println("这是我想看得" + result);
        if (result.isSuccess()) {
            //订单号
            JSONObject jsonObject = (JSONObject)result.getResult();
            System.out.println("这是我想看得" + jsonObject);
            String payInfoId = jsonObject.getString("payInfoId");
            this.logicHandle(payInfoId);
            return "success";
        }
        return "failure";
    }*/

    /**
     * 微信回调成功返回
     *
     * @param isSuccess 是否成功
     * @return
     */
    protected String wxResult(boolean isSuccess) {
        Map<String, String> xml = new HashMap<String, String>(2);
        xml.put("return_code", isSuccess ? "SUCCESS" : "FAIL");
        xml.put("return_msg", "OK");
        return WxPayKit.toXml(xml);
    }

}
